/**
 * 鼠标键盘操作功能模块
 * 包含所有鼠标点击、拖拽、键盘事件、框选等交互功能
 */

export class MouseKeyboardOperations {
  constructor(vueInstance) {
    this.vm = vueInstance
    this.isSelecting = false
    this.selectionStart = { x: 0, y: 0 }
    this.selectionCurrent = { x: 0, y: 0 }
    this.selectionBox = { left: 0, top: 0, width: 0, height: 0 }
    this.isCtrlPressed = false
    this.isDraggingMultiple = false
    this.isShiftDragging = false
    this.currentSelectingSatellite = null
    
    // 绑定键盘事件监听器
    this.bindKeyboardEvents()
  }

  /**
   * 绑定键盘事件监听器
   */
  bindKeyboardEvents() {
    document.addEventListener('keydown', this.handleKeyDown.bind(this))
    document.addEventListener('keyup', this.handleKeyUp.bind(this))
  }

  /**
   * 清理事件监听器
   */
  cleanup() {
    document.removeEventListener('keydown', this.handleKeyDown.bind(this))
    document.removeEventListener('keyup', this.handleKeyUp.bind(this))
  }

  /**
   * 键盘按下事件处理
   * @param {KeyboardEvent} event - 键盘事件
   */
  async handleKeyDown(event) {
    if (event.key === 'Escape') {
      // ESC键关闭编辑任务块弹窗
      if (this.vm.editItemVisible) {
        this.vm.closeEditItem()
        return
      }
    } else if (event.key === 'Control') {
      this.isCtrlPressed = true
      this.vm.isCtrlPressed = true
    } else if (event.key === 'Delete' && this.vm.selectedItems.length > 0) {
      // Delete键删除选中的任务块
      await this.vm.deleteSelectedItems()
    } else if (event.ctrlKey && event.key === 'z') {
      // Ctrl+Z撤销操作
      event.preventDefault() // 阻止浏览器默认的撤销行为
      this.vm.undo()
    } else if ((event.key === 'w' || event.key === 'W') && this.vm.selectedItems.length > 0) {
      // W键向前移动日期（减少startDay）
      event.preventDefault()
      await this.moveSelectedTasksHorizontally('backward')
    } else if ((event.key === 's' || event.key === 'S') && this.vm.selectedItems.length > 0) {
      // S键向后移动日期（增加startDay）
      event.preventDefault()
      await this.moveSelectedTasksHorizontally('forward')
    }
  }

  /**
   * 键盘释放事件处理
   * @param {KeyboardEvent} event - 键盘事件
   */
  handleKeyUp(event) {
    if (event.key === 'Control') {
      this.isCtrlPressed = false
      this.vm.isCtrlPressed = false
    }
  }

  /**
   * 任务块点击事件处理
   * @param {MouseEvent} event - 鼠标事件
   * @param {Object} item - 任务块项目
   */
  handleItemClick(event, item) {
    event.stopPropagation()
    
    if (event.ctrlKey) {
      // Ctrl+点击：切换选中状态
      const index = this.vm.selectedItems.findIndex(selected => selected.id === item.id)
      if (index > -1) {
        // 如果已选中，则取消选中
        this.vm.selectedItems.splice(index, 1)
      } else {
        // 如果未选中，则添加到选中列表
        this.vm.selectedItems.push(item)
      }
    } else if (event.shiftKey) {
      // Shift+点击：选中当前任务块及其后续所有任务块
      this.vm.selectedItems = this.getTaskAndSubsequentTasks(item, item.satelliteId)
    } else {
      // 普通单击：选中任务块
      this.vm.selectedItems = [item]
      this.vm.selectedScheduleItem = item
    }
  }

  /**
   * 任务块双击事件处理
   * @param {MouseEvent} event - 鼠标事件
   * @param {Object} item - 任务块项目
   */
  handleItemDoubleClick(event, item) {
    if (this.vm.taskBlockEditor) {
      this.vm.taskBlockEditor.handleItemDoubleClick(event, item)
    }
  }

  /**
   * 获取任务块及其后续所有任务块
   * @param {Object} currentTask - 当前任务块
   * @param {string} satelliteId - 卫星ID
   * @returns {Array} 任务块数组
   */
  getTaskAndSubsequentTasks(currentTask, satelliteId) {
    // 获取该卫星的所有任务块，按startDay排序
    const satelliteTasks = this.vm.scheduleItems
      .filter(item => item.satelliteId === satelliteId)
      .sort((a, b) => a.startDay - b.startDay)
    
    // 找到当前任务块在排序后数组中的位置
    const currentTaskIndex = satelliteTasks.findIndex(task => task.id === currentTask.id)
    
    if (currentTaskIndex === -1) {
      return [currentTask] // 如果找不到，只返回当前任务块
    }
    
    // 返回当前任务块及其后续所有任务块
    return satelliteTasks.slice(currentTaskIndex)
  }

  /**
   * 框选开始事件处理
   * @param {MouseEvent} event - 鼠标事件
   */
  onScheduleTableMouseDown(event) {
    // 只处理左键，并且不是在任务块上，也不是拖拽操作
    if (event.button !== 0 || 
        event.target.closest('.schedule-item') || 
        this.isDraggingMultiple) {
      return
    }
    
    console.log('框选开始 - 鼠标按下', {
      button: event.button,
      target: event.target.className,
      isCtrlPressed: this.isCtrlPressed
    })
    
    // 如果没有按住Ctrl键，清空现有选择
    if (!this.isCtrlPressed) {
      this.clearSelection()
    }
    
    // 获取表格容器元素
    const tableElement = document.querySelector('.schedule-table')
    if (!tableElement) {
      console.error('框选失败：找不到表格容器元素')
      return
    }
    
    const tableRect = tableElement.getBoundingClientRect()
    
    // 计算相对于表格容器的坐标，考虑滚动偏移
    this.selectionStart = {
      x: event.clientX - tableRect.left + tableElement.scrollLeft,
      y: event.clientY - tableRect.top + tableElement.scrollTop
    }
    this.selectionCurrent = { ...this.selectionStart }
    
    console.log('框选坐标初始化', {
      clientX: event.clientX,
      clientY: event.clientY,
      tableRect: tableRect,
      scrollLeft: tableElement.scrollLeft,
      scrollTop: tableElement.scrollTop,
      selectionStart: this.selectionStart
    })
    
    // 开始框选
    this.isSelecting = true
    this.vm.isSelecting = true
    this.updateSelectionBox()
    
    // 阻止默认行为
    event.preventDefault()
    event.stopPropagation()
  }

  /**
   * 框选移动事件处理
   * @param {MouseEvent} event - 鼠标事件
   */
  onScheduleTableMouseMove(event) {
    if (!this.isSelecting) return
    
    // 获取表格容器元素
    const tableElement = document.querySelector('.schedule-table')
    if (!tableElement) {
      console.error('框选移动失败：找不到表格容器元素')
      return
    }
    
    const tableRect = tableElement.getBoundingClientRect()
    
    // 计算当前位置相对于表格容器的坐标
    this.selectionCurrent = {
      x: event.clientX - tableRect.left + tableElement.scrollLeft,
      y: event.clientY - tableRect.top + tableElement.scrollTop
    }
    
    // 更新框选区域
    this.updateSelectionBox()
    
    // 实时更新选中的任务块
    this.updateSelectedItemsInBox()
  }

  /**
   * 框选结束事件处理
   * @param {MouseEvent} event - 鼠标事件
   */
  onScheduleTableMouseUp(event) {
    if (!this.isSelecting) return
    
    console.log('框选结束', {
      selectedItemsCount: this.vm.selectedItems.length,
      selectionBox: this.selectionBox
    })
    
    // 最后一次更新选中的任务块
    this.updateSelectedItemsInBox()
    
    // 结束框选
    this.isSelecting = false
    this.vm.isSelecting = false
    this.currentSelectingSatellite = null
  }

  /**
   * 鼠标离开表格事件处理
   * @param {MouseEvent} event - 鼠标事件
   */
  onScheduleTableMouseLeave(event) {
    if (this.isSelecting) {
      console.log('鼠标离开表格区域，结束框选')
      // 如果鼠标离开表格区域，结束框选
      this.isSelecting = false
      this.vm.isSelecting = false
      this.currentSelectingSatellite = null
    }
  }

  /**
   * 更新框选区域
   */
  updateSelectionBox() {
    const left = Math.min(this.selectionStart.x, this.selectionCurrent.x)
    const top = Math.min(this.selectionStart.y, this.selectionCurrent.y)
    const width = Math.abs(this.selectionCurrent.x - this.selectionStart.x)
    const height = Math.abs(this.selectionCurrent.y - this.selectionStart.y)
    
    this.selectionBox = { left, top, width, height }
    this.vm.selectionBox = this.selectionBox
  }

  /**
   * 更新框选区域内的选中任务块
   */
  updateSelectedItemsInBox() {
    if (!this.isSelecting) {
      console.log('updateSelectedItemsInBox: 不在框选状态，跳过')
      return
    }
    
    // 获取框选区域内的任务块
    const selectedInBox = []
    
    // 遍历所有任务块元素
    const taskElements = document.querySelectorAll('[data-task-id]')
    console.log('updateSelectedItemsInBox: 找到任务块元素数量', taskElements.length)
    
    if (taskElements.length === 0) {
      console.warn('updateSelectedItemsInBox: 没有找到任务块元素')
      return
    }
    
    taskElements.forEach(element => {
      const taskId = element.getAttribute('data-task-id')
      if (!taskId) {
        console.warn('updateSelectedItemsInBox: 元素缺少data-task-id属性', element)
        return
      }
      
      const task = this.vm.scheduleItems.find(item => item.id == taskId)
      if (!task) {
        console.warn('updateSelectedItemsInBox: 找不到对应的任务块数据', taskId)
        return
      }
      
      if (this.isElementInSelectionBox(element)) {
        selectedInBox.push(task)
      }
    })
    
    console.log('updateSelectedItemsInBox: 框选区域内的任务块', {
      count: selectedInBox.length,
      taskIds: selectedInBox.map(t => t.id),
      isCtrlPressed: this.isCtrlPressed
    })
    
    // 根据Ctrl键状态更新选中项
    if (this.isCtrlPressed) {
      // Ctrl+框选：添加到现有选择
      selectedInBox.forEach(task => {
        if (!this.vm.selectedItems.find(item => item.id === task.id)) {
          this.vm.selectedItems.push(task)
        }
      })
    } else {
      // 普通框选：替换现有选择
      this.vm.selectedItems = [...selectedInBox]
    }
  }

  /**
   * 检查元素是否在框选区域内
   * @param {HTMLElement} element - DOM元素
   * @returns {boolean} 是否在框选区域内
   */
  isElementInSelectionBox(element) {
    const rect = element.getBoundingClientRect()
    const tableElement = document.querySelector('.schedule-table')
    if (!tableElement) return false
    
    const tableRect = tableElement.getBoundingClientRect()
    
    // 计算元素相对于表格容器的位置
    const elementLeft = rect.left - tableRect.left + tableElement.scrollLeft
    const elementTop = rect.top - tableRect.top + tableElement.scrollTop
    const elementRight = elementLeft + rect.width
    const elementBottom = elementTop + rect.height
    
    // 计算框选区域的边界
    const selectionLeft = this.selectionBox.left
    const selectionTop = this.selectionBox.top
    const selectionRight = selectionLeft + this.selectionBox.width
    const selectionBottom = selectionTop + this.selectionBox.height
    
    // 检查是否有重叠
    return !(elementRight < selectionLeft || 
             elementLeft > selectionRight || 
             elementBottom < selectionTop || 
             elementTop > selectionBottom)
  }

  /**
   * 任务块拖拽开始事件处理
   * @param {DragEvent} event - 拖拽事件
   * @param {Object} item - 任务块项目
   * @param {number} index - 索引
   * @param {string} satelliteId - 卫星ID
   */
  onScheduleItemDragStart(event, item, index, satelliteId) {
    // 检测是否按住Shift键
    const isShiftPressed = event.shiftKey
    this.isShiftDragging = isShiftPressed
    
    if (isShiftPressed) {
      // Shift+拖拽模式：选中当前任务块及其后续所有任务块
      this.vm.selectedItems = this.getTaskAndSubsequentTasks(item, satelliteId)
    } else {
      // 普通拖拽模式：如果当前项未被选中，则只选中当前项
      if (!this.vm.isItemSelected(item.id)) {
        this.vm.selectedItems = [item]
      }
    }
    
    // 检查是否拖拽多个任务块
    const isDraggingMultiple = this.vm.selectedItems.length > 1
    this.isDraggingMultiple = isDraggingMultiple
    
    // 计算鼠标在任务块内的相对位置（以天为单位）
    const taskElement = event.target.closest('.schedule-item')
    const cellElement = event.target.closest('.schedule-cell')
    let dragOffsetDays = 0
    
    if (taskElement && cellElement) {
      const taskRect = taskElement.getBoundingClientRect()
      const cellRect = cellElement.getBoundingClientRect()
      const cellHeight = cellRect.height
      const mouseOffsetY = event.clientY - taskRect.top
      
      // 计算鼠标点击位置相对于任务块开始的天数偏移
      dragOffsetDays = Math.floor(mouseOffsetY / cellHeight)
      // 确保偏移量在合理范围内
      dragOffsetDays = Math.max(0, Math.min(dragOffsetDays, item.duration - 1))
    }
    
    // 记录当前拖拽的基准任务块（鼠标所在的任务块）
    const baseTaskItem = item
    
    // 隐藏被拖拽的任务块（不在原位置显示）
    if (isDraggingMultiple) {
      // 隐藏所有选中的任务块
      this.vm.selectedItems.forEach(selectedItem => {
        const elements = document.querySelectorAll(`[data-task-id="${selectedItem.id}"]`)
        elements.forEach(el => {
          el.style.opacity = '0'
          el.style.visibility = 'hidden'
        })
      })
    } else {
      // 隐藏单个任务块
      const elements = document.querySelectorAll(`[data-task-id="${item.id}"]`)
      elements.forEach(el => {
        el.style.opacity = '0'
        el.style.visibility = 'hidden'
      })
    }
    
    if (isDraggingMultiple) {
      // 多选拖拽：传递所有选中的任务块和源卫星ID
      event.dataTransfer.setData('text/plain', JSON.stringify({
        items: this.vm.selectedItems,
        sourceSatelliteId: satelliteId,
        isMultipleItemDrag: true,
        dragOffsetDays: dragOffsetDays,
        baseTaskItem: baseTaskItem, // 鼠标所在的基准任务块
        isShiftDragging: this.isShiftDragging // 是否为Shift+拖拽模式
      }))
    } else {
      // 单个拖拽：传递任务块数据和源卫星ID
      event.dataTransfer.setData('text/plain', JSON.stringify({
        item: item,
        sourceIndex: index,
        sourceSatelliteId: satelliteId,
        isScheduleItemReorder: true,
        dragOffsetDays: dragOffsetDays
      }))
    }
    
    event.dataTransfer.effectAllowed = 'move'
  }

  /**
   * 任务块拖拽结束事件处理
   * @param {DragEvent} event - 拖拽事件
   * @param {Object} item - 任务块项目
   */
  onScheduleItemDragEnd(event, item) {
    // 确保恢复任务块的可见性（防止拖拽被取消时任务块仍然隐藏）
    this.restoreTaskVisibility()
    
    // 重置Shift+拖拽标志
    this.isShiftDragging = false
    
    // 清空选中状态（确保拖拽结束后选中状态被清除）
    this.clearSelection()
  }

  /**
   * 恢复任务块可见性
   */
  restoreTaskVisibility() {
    const hiddenElements = document.querySelectorAll('[data-task-id]')
    hiddenElements.forEach(el => {
      el.style.opacity = ''
      el.style.visibility = ''
    })
  }

  /**
   * 单元格拖拽悬停事件处理
   * @param {DragEvent} event - 拖拽事件
   * @param {string} satelliteId - 卫星ID
   * @param {number} timeIndex - 时间索引
   */
  onCellDragOver(event, satelliteId, timeIndex) {
    event.preventDefault()
    
    // 检查是否允许在此位置拖放
    try {
      const dragDataString = event.dataTransfer.getData('text/plain')
      if (dragDataString) {
        const dragData = JSON.parse(dragDataString)
        
        // 只允许在同一卫星内拖拽
        if (dragData.sourceSatelliteId && dragData.sourceSatelliteId === satelliteId) {
          // 移除严格的重叠检测，允许拖动到任何位置
          // 重叠问题将在 onCellDrop 中通过 autoArrangeSubsequentTasks 自动解决
          event.dataTransfer.dropEffect = 'move'
        } else {
          // 不允许跨卫星拖拽
          event.dataTransfer.dropEffect = 'none'
        }
      } else {
        event.dataTransfer.dropEffect = 'move'
      }
    } catch (error) {
      // 如果解析失败，默认允许
      event.dataTransfer.dropEffect = 'move'
    }
  }

  /**
   * 单元格拖拽放置事件处理
   * @param {DragEvent} event - 拖拽事件
   * @param {string} targetSatelliteId - 目标卫星ID
   * @param {number} targetTimeIndex - 目标时间索引
   */
  onCellDrop(event, targetSatelliteId, targetTimeIndex) {
    event.preventDefault()
    event.stopPropagation()
    
    // 在移动前保存历史记录
    this.vm.saveToHistory()
    
    // 设置标志防止watcher重复保存
    this.vm.isUpdatingScheduleItems = true
    
    const dragData = JSON.parse(event.dataTransfer.getData('text/plain'))
    
    if (dragData.isMultipleItemDrag) {
      this.handleMultipleItemDrop(dragData, targetSatelliteId, targetTimeIndex)
    } else if (dragData.isScheduleItemReorder) {
      this.handleSingleItemDrop(dragData, targetSatelliteId, targetTimeIndex)
    }
    
    // 重置拖拽状态
    this.isDraggingMultiple = false
    
    // 重置标志
    this.vm.isUpdatingScheduleItems = false
    
    // 强制Vue重新渲染，然后恢复任务块的可见性
    this.vm.$nextTick(() => {
      this.restoreTaskVisibility()
    })
  }

  /**
   * 处理多个任务块拖拽放置
   * @param {Object} dragData - 拖拽数据
   * @param {string} targetSatelliteId - 目标卫星ID
   * @param {number} targetTimeIndex - 目标时间索引
   */
  handleMultipleItemDrop(dragData, targetSatelliteId, targetTimeIndex) {
    const sourceSatelliteId = dragData.sourceSatelliteId
    
    // 只允许在同一卫星内拖拽
    if (sourceSatelliteId !== targetSatelliteId) {
      console.warn('不允许跨卫星拖拽任务块')
      return
    }
    
    // 获取所有选中任务块的ID
    const selectedIds = this.vm.selectedItems.map(item => item.id)
    
    // 按照原有顺序排序选中的任务块
    const sortedSelectedItems = this.vm.selectedItems.sort((a, b) => a.startDay - b.startDay)
    
    // 计算原有任务块之间的间隔
    const originalIntervals = []
    for (let i = 0; i < sortedSelectedItems.length - 1; i++) {
      const currentItem = sortedSelectedItems[i]
      const nextItem = sortedSelectedItems[i + 1]
      const interval = nextItem.startDay - (currentItem.startDay + currentItem.duration)
      originalIntervals.push(interval)
    }
    
    // 计算保持间隔后的总占用时间
    const totalDuration = sortedSelectedItems.reduce((total, item) => total + item.duration, 0) + 
                         originalIntervals.reduce((total, interval) => total + interval, 0)
    
    // 获取基准任务块（鼠标所在的任务块）
    const baseTaskItem = dragData.baseTaskItem
    const dragOffsetDays = dragData.dragOffsetDays || 0
    
    // 计算基准任务块在排序后数组中的位置
    const baseTaskIndex = sortedSelectedItems.findIndex(item => item.id === baseTaskItem.id)
    
    // 计算基准任务块之前的所有任务块和间隔的总时间
    let timeBeforeBase = 0
    for (let i = 0; i < baseTaskIndex; i++) {
      timeBeforeBase += sortedSelectedItems[i].duration
      if (i < originalIntervals.length) {
        timeBeforeBase += originalIntervals[i]
      }
    }
    
    // 计算实际放置位置：目标位置 - 拖拽偏移量 - 基准任务块之前的时间
    let calculatedStartDay = targetTimeIndex - dragOffsetDays - timeBeforeBase
    
    // 智能对齐：如果计算出的起始位置在日期内部（小数部分），自动对齐到该日期的开始
    const actualStartDay = Math.max(0, Math.floor(calculatedStartDay))
    
    // 自动排列后续可能冲突的任务块
    this.vm.autoArrangeSubsequentTasks(
      targetSatelliteId, 
      actualStartDay, 
      totalDuration, 
      selectedIds
    )
    
    // 更新所有选中任务块的开始时间（保持原有间隔）
    let currentStartDay = actualStartDay
    sortedSelectedItems.forEach((item, index) => {
      const itemIndex = this.vm.scheduleItems.findIndex(scheduleItem => scheduleItem.id === item.id)
      if (itemIndex > -1) {
        // 重新计算actualStartDate
        const newActualStartDate = new Date(this.vm.startDate)
        newActualStartDate.setDate(newActualStartDate.getDate() + currentStartDay)
        
        this.vm.scheduleItems[itemIndex] = {
          ...this.vm.scheduleItems[itemIndex],
          startDay: currentStartDay,
          actualStartDate: newActualStartDate.toISOString().split('T')[0]
        }
        // 移动到下一个任务块位置：当前任务块结束 + 原有间隔
        currentStartDay += item.duration
        if (index < originalIntervals.length) {
          currentStartDay += originalIntervals[index]
        }
      }
    })
    
    // 验证没有重叠（开发调试）
    this.vm.validateNoOverlap(targetSatelliteId)
    
    // 进行全局设备冲突检测（因为设备冲突可能涉及多个卫星）
    const conflicts = this.vm.detectDeviceConflicts() // 检测所有卫星
    if (conflicts.length > 0) {
      this.vm.markConflictingTasks(conflicts)
    } else {
      this.vm.clearConflictMarks()
    }
    
    // 清空选中状态
    this.clearSelection()
  }

  /**
   * 处理单个任务块拖拽放置
   * @param {Object} dragData - 拖拽数据
   * @param {string} targetSatelliteId - 目标卫星ID
   * @param {number} targetTimeIndex - 目标时间索引
   */
  handleSingleItemDrop(dragData, targetSatelliteId, targetTimeIndex) {
    const item = dragData.item
    const sourceSatelliteId = dragData.sourceSatelliteId
    
    if (!item) {
      return
    }
    
    // 只允许在同一卫星内拖拽
    if (sourceSatelliteId !== targetSatelliteId) {
      console.warn('不允许跨卫星拖拽任务块')
      return
    }
    
    // 计算考虑拖拽偏移量的实际放置位置
    const dragOffsetDays = dragData.dragOffsetDays || 0
    let calculatedStartDay = targetTimeIndex - dragOffsetDays
    
    // 智能对齐：如果计算出的起始位置在日期内部（小数部分），自动对齐到该日期的开始
    const actualStartDay = Math.max(0, Math.floor(calculatedStartDay))
    
    // 自动排列后续可能冲突的任务块
    this.vm.autoArrangeSubsequentTasks(
      targetSatelliteId, 
      actualStartDay, 
      item.duration, 
      [item.id]
    )
    
    // 更新任务块的开始时间和实际起始日期
    const itemIndex = this.vm.scheduleItems.findIndex(scheduleItem => scheduleItem.id === item.id)
    if (itemIndex > -1) {
      // 计算新的实际起始日期
      const newActualStartDate = new Date(this.vm.startDate)
      newActualStartDate.setDate(newActualStartDate.getDate() + actualStartDay)
      
      this.vm.scheduleItems[itemIndex] = {
        ...this.vm.scheduleItems[itemIndex],
        startDay: actualStartDay,
        actualStartDate: newActualStartDate.toISOString().split('T')[0]
      }
    }
    
    // 验证没有重叠（开发调试）
    this.vm.validateNoOverlap(targetSatelliteId)
    
    // 进行全局设备冲突检测
    const conflicts = this.vm.detectDeviceConflicts()
    if (conflicts.length > 0) {
      this.vm.markConflictingTasks(conflicts)
    } else {
      this.vm.clearConflictMarks()
    }
    
    // 清空选中状态（保持与多选拖拽一致的行为）
    this.clearSelection()
  }

  /**
   * 单元格拖拽进入事件处理
   * @param {DragEvent} event - 拖拽事件
   * @param {string} satelliteId - 卫星ID
   * @param {number} timeIndex - 时间索引
   */
  onCellDragEnter(event, satelliteId, timeIndex) {
    event.preventDefault()
    // 可以在这里添加视觉反馈逻辑
  }

  /**
   * 单元格拖拽离开事件处理
   * @param {DragEvent} event - 拖拽事件
   * @param {string} satelliteId - 卫星ID
   * @param {number} timeIndex - 时间索引
   */
  onCellDragLeave(event, satelliteId, timeIndex) {
    // 可以在这里添加清除视觉反馈的逻辑
  }

  /**
   * 单元格点击事件处理
   * @param {MouseEvent} event - 鼠标事件
   * @param {string} satelliteId - 卫星ID
   * @param {number} timeIndex - 时间索引
   */
  handleCellClick(event, satelliteId, timeIndex) {
    // 如果点击的是空白区域（不是任务块），清空选中状态
    if (event.target.classList.contains('schedule-cell') || event.target.classList.contains('schedule-content')) {
      // 只有在单元格未被占用时才清空选中状态
      if (!this.vm.isCellOccupied(satelliteId, timeIndex)) {
        this.clearSelection()
      }
    }
  }

  /**
   * 显示右键上下文菜单
   * @param {MouseEvent} event - 鼠标事件
   * @param {Object} item - 任务块项目
   */
  showContextMenu(event, item) {
    if (this.vm.contextMenuOps) {
      this.vm.contextMenuOps.showContextMenu(event, item)
    }
  }

  /**
   * 显示单元格右键上下文菜单
   * @param {MouseEvent} event - 鼠标事件
   * @param {string} satelliteId - 卫星ID
   * @param {number} timeIndex - 时间索引
   */
  showCellContextMenu(event, satelliteId, timeIndex) {
    if (this.vm.contextMenuOps) {
      this.vm.contextMenuOps.showCellContextMenu(event, satelliteId, timeIndex)
    }
  }

  /**
   * 清空选择
   */
  clearSelection() {
    this.vm.selectedItems = []
    // 强制触发视图更新
    this.vm.$nextTick(() => {
      this.vm.$forceUpdate()
    })
  }

  /**
   * 水平移动选中的任务块（日期移动）
   * @param {string} direction - 移动方向 ('backward' | 'forward')
   */
  async moveSelectedTasksHorizontally(direction) {
    if (this.vm.selectedItems.length === 0) {
      console.log('没有选中的任务块')
      return
    }
    
    // 预检查：检查关键任务块是否有冲突
    let criticalItem
    if (direction === 'backward') {
      // W键移动时，检查最开始的任务块（startDay最小的）
      criticalItem = this.vm.selectedItems.reduce((earliest, current) => 
        current.startDay < earliest.startDay ? current : earliest
      )
    } else {
      // S键移动时，检查最末尾的任务块（startDay + duration最大的）
      criticalItem = this.vm.selectedItems.reduce((latest, current) => 
        (current.startDay + current.duration) > (latest.startDay + latest.duration) ? current : latest
      )
    }
    
    // 计算关键任务块的目标位置
    let criticalTargetStartDay
    if (direction === 'backward') {
      criticalTargetStartDay = criticalItem.startDay - 1
    } else {
      criticalTargetStartDay = criticalItem.startDay + 1
    }
    
    // 检查关键任务块的目标位置是否有效
    if (criticalTargetStartDay < 1) {
      console.log(`移动失败：最开始的任务块 ${criticalItem.title} 已到达最早日期`)
      return
    }
    
    // 检查关键任务块的目标位置是否有冲突
    const selectedItemIds = this.vm.selectedItems.map(item => item.id)
    const criticalHasConflict = this.vm.checkTaskConflictAtPosition(
      criticalItem.satelliteId,
      criticalTargetStartDay,
      criticalItem.duration,
      selectedItemIds
    )
    
    if (criticalHasConflict) {
      console.log(`移动失败：关键任务块 ${criticalItem.title} 在目标位置有冲突`)
      return
    }
    
    // 保存当前状态到历史记录
    this.vm.saveToHistory()
    
    let moveCount = 0
    let failCount = 0
    
    // 移动所有选中的任务块
    for (const selectedItem of this.vm.selectedItems) {
      // 计算目标日期
      let targetStartDay
      if (direction === 'backward') {
        targetStartDay = selectedItem.startDay - 1
      } else { // forward
        targetStartDay = selectedItem.startDay + 1
      }
      
      // 检查目标日期是否有效（不能小于1）
      if (targetStartDay < 1) {
        console.log(`任务块 ${selectedItem.title} 无法向前移动：已到达最早日期`)
        failCount++
        continue
      }
      
      // 检查目标位置是否有冲突
      const hasConflict = this.vm.checkTaskConflictAtPosition(
        selectedItem.satelliteId,
        targetStartDay,
        selectedItem.duration,
        selectedItemIds
      )
      
      if (hasConflict) {
        console.log(`任务块 ${selectedItem.title} 无法移动到目标位置：存在冲突`)
        failCount++
        continue
      }
      
      // 执行移动
      const itemIndex = this.vm.scheduleItems.findIndex(item => item.id === selectedItem.id)
      if (itemIndex > -1) {
        // 计算新的实际起始日期
        const newActualStartDate = new Date(this.vm.startDate)
        newActualStartDate.setDate(newActualStartDate.getDate() + targetStartDay)
        
        this.vm.scheduleItems[itemIndex] = {
          ...this.vm.scheduleItems[itemIndex],
          startDay: targetStartDay,
          actualStartDate: newActualStartDate.toISOString().split('T')[0]
        }
        
        // 同步更新selectedItems中的数据
        const selectedIndex = this.vm.selectedItems.findIndex(item => item.id === selectedItem.id)
        if (selectedIndex > -1) {
          this.vm.selectedItems[selectedIndex] = {
            ...this.vm.selectedItems[selectedIndex],
            startDay: targetStartDay,
            actualStartDate: newActualStartDate.toISOString().split('T')[0]
          }
        }
        
        moveCount++
      }
    }
    
    console.log(`移动完成：成功移动 ${moveCount} 个任务块，失败 ${failCount} 个`)
    
    // 进行全局设备冲突检测
    const conflicts = this.vm.detectDeviceConflicts()
    if (conflicts.length > 0) {
      this.vm.markConflictingTasks(conflicts)
    } else {
      this.vm.clearConflictMarks()
    }
    
    // 强制更新视图
    this.vm.$forceUpdate()
  }
}